package com.uziot.bucket.sequence.service;

import com.uziot.bucket.sequence.dao.domain.Sequences;
import com.uziot.bucket.sequence.dao.mapper.SequencesMapper;
import com.uziot.bucket.sequence.util.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author shidt
 * @version V1.0
 * @className SequencesConfiguration
 * @date 2021-01-08 23:33:22
 * @description 基于内存的序列管理，数据库序列对象管理内存存储
 */
@Component
public class SequencesConfiguration {
    private static final Logger log = LoggerFactory.getLogger(SequencesConfiguration.class);

    private static final Map<String, Sequences> CONFIGURATION = new ConcurrentHashMap<>();
    private static final Map<String, Sequences> REGEXP_CONFIGURATION = new ConcurrentHashMap<>();

    @Resource
    private SequencesMapper sequencesMapper;

    /**
     * 初始化加载序列列表到容器中，也可调用此方法重新加载
     */
    @PostConstruct
    public void initConfiguration() {
        if (log.isInfoEnabled()) {
            log.info("Loading Start Sequences from DataBase.......");
        }
        List<Sequences> allSequences = sequencesMapper.getAllSequences();

        allSequences.forEach(sequences -> {
            String seqName = sequences.getSeqName();
            // 添加序列配置信息
            CONFIGURATION.put(seqName, sequences);
            // 添加序列名称管理
            SequencesNameManager snm = SequencesNameManager.getInstance();
            if (!snm.contains(seqName)) {
                snm.addName(seqName);
            }
        });
        if (log.isInfoEnabled()) {
            log.info("Loading Success Sequences from DataBase.......");
        }

    }

    /**
     * 重新加载数据库序列参数配置到内存中
     */
    public synchronized void reloadConfiguration() {
        this.initConfiguration();
    }

    /**
     * 设置序列配置
     *
     * @param seqName   seqName
     * @param sequences sequences
     */
    protected static void setSequences(String seqName, Sequences sequences) {
        if (null == seqName) {
            throw new IllegalArgumentException("sequences name must input.");
        }
        if (null == sequences) {
            throw new IllegalArgumentException("sequences must input.");
        }
        CONFIGURATION.put(seqName, sequences);
    }

    /**
     * 获取序列配置
     *
     * @param seqName seqName
     * @return Sequences
     */
    public static Sequences getSequences(String seqName) {
        if (CONFIGURATION.containsKey(seqName)) {
            return CONFIGURATION.get(seqName);
        } else {
            return getRegexpSequences(seqName);
        }
    }

    /**
     * 设置正则序列配置
     *
     * @param seqName   seqName
     * @param sequences sequences
     */
    protected static void setRegexpSequences(String seqName, Sequences sequences) {
        if (null == seqName) {
            throw new IllegalArgumentException("regexp sequences name must input.");
        }
        if (null == sequences) {
            throw new IllegalArgumentException("regexp sequences must input.");
        }
        REGEXP_CONFIGURATION.put(seqName, sequences);
    }

    /**
     * 获取序列配置
     *
     * @param seqName seqName
     * @return Sequences
     */
    private static Sequences getRegexpSequences(String seqName) {
        String regexp = regexpContainsKey(seqName);
        if (null != regexpContainsKey(seqName)) {
            Sequences sequences = REGEXP_CONFIGURATION.get(regexp);

            Sequences seq = BeanUtils.copyProperties(sequences, Sequences.class);
            seq.setSeqName(seqName);
            return seq;
        }
        return new Sequences(seqName);
    }

    /**
     * 获取正则表达式Key
     *
     * @param seqName seqName
     * @return String
     */
    private static String regexpContainsKey(String seqName) {
        Pattern p;
        Matcher m;
        for (String key : REGEXP_CONFIGURATION.keySet()) {
            p = Pattern.compile(key);
            m = p.matcher(seqName);
            if (m.find()) {
                return key;
            }
        }
        return null;
    }

    /**
     * 是否包含序列配置
     *
     * @param seqName seqName
     * @return boolean
     */
    public static boolean containsKey(String seqName) {
        if (CONFIGURATION.containsKey(seqName)) {
            return true;
        }
        return regexpContainsKey(seqName) != null;
    }
}
